home *** CD-ROM | disk | FTP | other *** search
- /* Send and receive IP datagrams on serial lines. Compatible with SLIP
- * under Berkeley Unix.
- */
- #include <stdio.h>
- #include "global.h"
- #include "mbuf.h"
- #include "iface.h"
- #include "ax25.h"
- #include "slip.h"
- #include "asy.h"
- #include "combios.h"
- #include "trace.h"
-
- /* Slip level control structure */
- struct slip slip[ASY_MAX];
-
- static int asy_start();
-
- /* Send routine for point-to-point slip
- * This is a trivial function since there is no slip link-level header
- */
- int
- slip_send(data,interface,gateway,precedence,delay,throughput,reliability)
- struct mbuf *data; /* Buffer to send */
- struct interface *interface; /* Pointer to interface control block */
- int32 gateway; /* Ignored (SLIP is point-to-point) */
- char precedence;
- char delay;
- char throughput;
- char reliability;
- {
- if(interface == NULLIF){
- free_p(data);
- return -1;
- }
- dump(interface,IF_TRACE_OUT,TRACE_IP,data);
- return (*interface->raw)(interface,data);
- }
- /* Send a raw slip frame -- also trivial */
- int
- slip_raw(interface,data)
- struct interface *interface;
- struct mbuf *data;
- {
- /* Queue a frame on the slip output queue and start transmitter */
- return slipq(interface->dev,data);
- }
- /* Encode a raw packet in slip framing, put on link output queue, and kick
- * transmitter
- */
- static int
- slipq(dev,data)
- int16 dev; /* Serial line number */
- struct mbuf *data; /* Buffer to be sent */
- {
- register struct slip *sp;
- struct mbuf *slip_encode(),*bp;
-
- if((bp = slip_encode(data)) == NULLBUF)
- return -1;
-
- sp = &slip[dev];
- enqueue(&sp->sndq,bp);
- sp->sndcnt++;
- if(sp->tbp == NULLBUF)
- asy_start(dev);
- return 0;
- }
- /* Start output, if possible, on asynch device dev */
- static int
- asy_start(dev)
- int16 dev;
- {
- register struct slip *sp;
- int asy_output();
- #ifdef COMBIOS
- struct com *cp;
- unsigned char c;
- unsigned stat;
- int numsend;
- #endif
-
- #ifdef COMBIOS
- com[dev].stat |= (stat = combios(0x0300,dev));
- if(!(stat & 0x2000))
- #else
- if(!stxrdy(dev))
- #endif
- return -1; /* Transmitter not ready */
-
- sp = &slip[dev];
-
- if(sp->tbp != NULLBUF){
- #ifdef COMBIOS
- goto comsend; /* still something to send */
- #else
- /* transmission just completed */
- free_p(sp->tbp);
- sp->tbp = NULLBUF;
- #endif
- }
-
- if(sp->sndq == NULLBUF)
- return 0; /* No work */
-
- sp->tbp = dequeue(&sp->sndq);
- sp->sndcnt--;
-
- #ifdef COMBIOS
- comsend:
- cp = &com[dev]; /* quick ptr to our com */
-
- if ((numsend = cp->txbuf) == 0)
- numsend = cp->speed; /* enough for 10 seconds */
-
- while(--numsend && pullup(&sp->tbp,&c,1) == 1) {
- cp->stat |= (stat = combios(0x0100 | c,dev)) & 0x7f00;
- if (cp->txbuf == 0 && /* no explicit tx buffer max */
- (stat & 0xa000) != 0x2000) /* timeout or full */
- break;
- }
- #else
- asy_output(dev,sp->tbp->data,sp->tbp->cnt);
- #endif
- return 1;
- }
- /* Encode a packet in SLIP format */
- struct mbuf *
- slip_encode(bp)
- struct mbuf *bp;
- {
- struct mbuf *lbp; /* Mbuf containing line-ready packet */
- register char *cp;
- char c;
-
- /* Allocate output mbuf that's twice as long as the packet.
- * This is a worst-case guess (consider a packet full of FR_ENDs!)
- */
- lbp = alloc_mbuf(2*len_mbuf(bp) + 2);
- if(lbp == NULLBUF){
- /* No space; drop */
- free_p(bp);
- return NULLBUF;
- }
- cp = lbp->data;
-
- /* Flush out any line garbage */
- *cp++ = FR_END;
-
- /* Copy input to output, escaping special characters */
- while(pullup(&bp,&c,1) == 1){
- switch(uchar(c)){
- case FR_ESC:
- *cp++ = FR_ESC;
- *cp++ = T_FR_ESC;
- break;
- case FR_END:
- *cp++ = FR_ESC;
- *cp++ = T_FR_END;
- break;
- default:
- *cp++ = c;
- }
- }
- *cp++ = FR_END;
- lbp->cnt = cp - lbp->data;
- return lbp;
- }
- /* Process incoming bytes in SLIP format
- * When a buffer is complete, return it; otherwise NULLBUF
- */
- struct mbuf *
- slip_decode(sp,c)
- register struct slip *sp; /* Slip level control struct */
- char c; /* Incoming character */
- {
- struct mbuf *bp;
-
- switch(uchar(c)){
- case FR_END:
- bp = sp->rbp;
- sp->rbp = NULLBUF;
- sp->rcnt = 0;
- return bp; /* Will be NULLBUF if empty frame */
- case FR_ESC:
- sp->escaped = 1;
- return NULLBUF;
- }
- if(sp->escaped){
- /* Translate 2-char escape sequence back to original char */
- sp->escaped = 0;
- switch(uchar(c)){
- case T_FR_ESC:
- c = FR_ESC;
- break;
- case T_FR_END:
- c = FR_END;
- break;
- default:
- sp->errors++;
- break;
- }
- }
- /* We reach here with a character for the buffer;
- * make sure there's space for it
- */
- if(sp->rbp == NULLBUF){
- /* Allocate first mbuf for new packet */
- if((sp->rbp1 = sp->rbp = alloc_mbuf(SLIP_ALLOC)) == NULLBUF)
- return NULLBUF; /* No memory, drop */
- sp->rcp = sp->rbp->data;
- } else if(sp->rbp1->cnt == SLIP_ALLOC){
- /* Current mbuf is full; link in another */
- if((sp->rbp1->next = alloc_mbuf(SLIP_ALLOC)) == NULLBUF){
- /* No memory, drop whole thing */
- free_p(sp->rbp);
- sp->rbp = NULLBUF;
- sp->rcnt = 0;
- return NULLBUF;
- }
- sp->rbp1 = sp->rbp1->next;
- sp->rcp = sp->rbp1->data;
- }
- /* Store the character, increment fragment and total
- * byte counts
- */
- *sp->rcp++ = c;
- sp->rbp1->cnt++;
- sp->rcnt++;
- return NULLBUF;
- }
- /* Process SLIP line I/O */
- int
- doslip(interface)
- struct interface *interface;
- {
- #ifdef COMBIOS
- unsigned stat;
- #else
- char c;
- #endif
- struct mbuf *bp;
- register struct slip *sp;
- int16 dev;
- int rv = 0;
- int16 asy_recv();
-
- dev = interface->dev;
- sp = &slip[dev];
-
- #ifdef COMBIOS
- /* Process any pending input */
- fossil:
- com[dev].stat |= (stat = combios(0x0300,dev));
-
- while(stat & 0x0100) {
- com[dev].stat |= (stat = combios(0x0200,dev));
-
- if((bp = slip_decode(sp,stat & 0xff)) != NULLBUF) {
- if (com[dev].stat & 0x1a00) /* error detected? */
- free(bp); /* discard frame */
- else
- (*sp->recv)(interface,bp);
-
- com[dev].stat = 0;
- rv++;
- }
-
- if(com[dev].drtype == 3)
- goto fossil; /* FOSSIL needs new status */
- }
-
- /* Kick the transmitter if it's idle */
- if(stat & 0x2000)
- if (asy_start(dev))
- rv++;
- #else
- /* Process any pending input */
- while(asy_recv(dev,&c,1) != 0)
- if((bp = slip_decode(sp,c)) != NULLBUF){
- (*sp->recv)(interface,bp);
- rv++;
- }
-
- /* Kick the transmitter if it's idle */
- if(sp->sndq != NULLBUF){
- asy_start(dev);
- rv++;
- }
- #endif
-
- return rv; /* processed packets */
- }
- /* Unwrap incoming SLIP packets -- trivial operation since there's no
- * link level header
- */
- void
- slip_recv(interface,bp)
- struct interface *interface;
- struct mbuf *bp;
- {
- int ip_route();
-
- /* By definition, all incoming packets are "addressed" to us */
- dump(interface,IF_TRACE_IN,TRACE_IP,bp);
- ip_route(bp,0);
- }
-